package znet

import (
	"fmt"

	"github.com/desyang-hub/zinx_demo/utils"
	"github.com/desyang-hub/zinx_demo/zface"
)

type MsgHandler struct {
	Apis map[uint32]zface.IRouter

	TaskQueue      []chan zface.IRequest
	WorkerPoolSize uint32
}

func (mh *MsgHandler) DoMsgHandler(request zface.IRequest) {
	// 查找msgID对应的Router
	router, ok := mh.Apis[request.GetMessage().GetMsgID()]

	if !ok {
		fmt.Printf("[warning] msgID %d Router not Register.\n", request.GetMessage().GetMsgID())
		return
	}

	// 根据ID对应的Router处理对应的Request
	router.PreHandle(request)
	router.Handle(request)
	router.PostHandle(request)
}

func (mh *MsgHandler) AddRouter(msgID uint32, router zface.IRouter) {
	if _, ok := mh.Apis[msgID]; ok {
		fmt.Printf("[Error] Register Router err, msgID %d always exists.\n", msgID)
		return
	}

	mh.Apis[msgID] = router
}

// 启用Worker线程池
func (mh *MsgHandler) StartWorkerPool() {
	for i := 0; i < int(mh.WorkerPoolSize); i += 1 {
		mh.TaskQueue[i] = make(chan zface.IRequest, utils.AppContext.MaxTaskQueueSize) // 创建消息队列

		fmt.Printf("Worker id = %d is started.\n", i)

		// 使用一个Gorountine去监听这个消息队列
		go mh.StartOneWorker(i)
	}
}

func (mh *MsgHandler) StartOneWorker(workerID int) {
	// 和select的功能是一致的，都会阻塞
	for request := range mh.TaskQueue[workerID] {
		mh.DoMsgHandler(request)
	}
}

func (mh *MsgHandler) SendRequestToMaskQueue(mid uint32, request zface.IRequest) {

	// 采用轮询策略
	mh.TaskQueue[mid%mh.WorkerPoolSize] <- request
}

func NewMsgHandler() zface.IMsgHandler {
	return &MsgHandler{
		Apis:           make(map[uint32]zface.IRouter),
		TaskQueue:      make([]chan zface.IRequest, utils.AppContext.WorkerPoolSize),
		WorkerPoolSize: utils.AppContext.WorkerPoolSize,
	}
}
